//; ---------------------------------------------------------------------------
//; Object 18 - platforms	(GHZ, SYZ, SLZ)
//; ---------------------------------------------------------------------------

#include "platforms.h"

#include "../sprite.h"
#include "../objectsystemNEWER.h"

static object *obj;

//EXTERN DEFINITIONS HERE


//; ---------------------------------------------------------------------------
//; Animation script - (OBJECT)
//; ---------------------------------------------------------------------------

//; ---------------------------------------------------------------------------
//; Sprite mappings - (OBJECT)
//; ---------------------------------------------------------------------------


//==========

void (*Plat_Index[5])() = { Plat_Main, Plat_Solid, Plat_Action2, Plat_Delete, Plat_Action };

//BasicPlatform:					; XREF: Obj_Index
void BasicPlatform(object *_obj)
{
    obj = _obj;

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0
    byte routine = obj->Routine/2;

    //move.w	Plat_Index(pc,d0.w),d1
    //jmp	Plat_Index(pc,d1.w)
    (*Plat_Index[routine])();
}

//; ===========================================================================

//Plat_Main:	; Routine 0
void Plat_Main()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;

    //move.w	#$4000,obGfx(a0)
    obj->Gfx = 0x4000;

    //move.l	#Map_Plat_GHZ,obMap(a0)
    obj->Map = Map_Plat_GHZ;

    //move.b	#$20,obActWid(a0)
    obj->ActionWidth = 32;

    //cmpi.b	#id_SYZ,(v_zone).w ; check if level is SYZ
    //bne.s	@notSYZ
    //move.l	#Map_Plat_SYZ,obMap(a0) ; SYZ specific code
    //move.b	#$20,obActWid(a0)
    //@notSYZ:
    //cmpi.b	#id_SLZ,(v_zone).w ; check if level is SLZ
    //bne.s	@notSLZ
    //move.l	#Map_Plat_SLZ,obMap(a0) ; SLZ specific code
    //move.b	#$20,obActWid(a0)
    //move.w	#$4000,obGfx(a0)
    //move.b	#3,obSubtype(a0)
    //@notSLZ:

    //move.b	#4,obRender(a0)
    obj->Render = 4;

    //move.b	#4,obPriority(a0)
    obj->Priority = 4;

    //move.w	obY(a0),$2C(a0)
    ptrsetobjvariableword(0x2C, obj, obj->Y);

    //move.w	obY(a0),$34(a0)
    ptrsetobjvariableword(0x34, obj, obj->Y);

    //move.w	obX(a0),$32(a0)
    ptrsetobjvariableword(0x32, obj, obj->X);

    //move.w	#$80,obAngle(a0)
    obj->Angle = 0x80;

    //moveq	#0,d1
    long startFrame = 0;

    //move.b	obSubtype(a0),d0
    byte platType = obj->Subtype;

    //cmpi.b	#$A,d0		; is object type $A (large platform)?
    //bne.s	@setframe	; if not, branch
    if (platType == 10)
    {
        //addq.b	#1,d1		; use frame #1
        startFrame += 1;
        
	//move.b	#$20,obActWid(a0) ; set width
        obj->ActionWidth = 32;
    }

    //@setframe:
    //move.b	d1,obFrame(a0)	; set frame to d1 
    obj->Frame = startFrame;

}

//; ===========================================================================

//Plat_Solid:	; Routine 2
void Plat_Solid()
{
    //tst.b	$38(a0)
    //beq.s	loc_7EE0
    if (obj->Variables[0x38-0x28] != 0)
    {
        //subq.b	#4,$38(a0)
        obj->Variables[0x38-0x28] = obj->Variables[0x38-0x28] - 4;
    }
    
    //loc_7EE0:
    //moveq	#0,d1
    //move.b	obActWid(a0),d1
    byte actionWidth = obj->ActionWidth;

    //bsr.w	PlatformObject
    PlatformObject(obj, actionWidth);

    Plat_Action();
}
  
//Plat_Action:	; Routine 8
void Plat_Action()
{
    //bsr.w	Plat_Move
    Plat_Move();

    //bsr.w	Plat_Nudge
    Plat_Nudge();

    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //bra.w	Plat_ChkDel
    Plat_ChkDel();
}
//; ===========================================================================

//Plat_Action2:	; Routine 4
void Plat_Action2()
{
    //cmpi.b	#$40,$38(a0)
    //beq.s	loc_7F06
    if (obj->Variables[0x38-0x28] != 0x40) 
    {
        //addq.b	#4,$38(a0)
        obj->Variables[0x38-0x28] = obj->Variables[0x38-0x28] + 4;        
    }
    
    //loc_7F06:
    //moveq	#0,d1
    //move.b	obActWid(a0),d1
    byte actionWidth = obj->ActionWidth;

    signed short distPlayerLPlatformX;
    //bsr.w	ExitPlatform
    ExitPlatform(obj, actionWidth, distPlayerLPlatformX);

    //move.w	obX(a0),-(sp)
    word oldX = obj->X;

    //bsr.w	Plat_Move
    Plat_Move();

    //bsr.w	Plat_Nudge
    Plat_Nudge();

    //move.w	(sp)+,d2
   
    //bsr.w	MvSonicOnPtfm2
    MvSonicOnPtfm2(obj, oldX); 

    //bsr.w	DisplaySprite
    DisplaySprite(obj);		

    //bra.w	Plat_ChkDel
    Plat_ChkDel();

}   //rts

//; ---------------------------------------------------------------------------
//; Subroutine to	move platform slightly when you	stand on it
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

//moves platform in the y direction at a sinusoid rate, dependent on a 'nudgeAngle' set at init and accumulated/decumulated at stand/leave respectively
//Plat_Nudge:				; XREF: Plat_Action; Plat_Action2
void Plat_Nudge()
{
    //move.b	$38(a0),d0
    byte nudgeAngle = obj->Variables[0x38-0x28];

    signed short sine, cosine;
    //bsr.w	CalcSine
    CalcSine(nudgeAngle, sine, cosine);

    //move.w	#$400,d1
    word scaleVal = 0x400;

    //muls.w	d1,d0
    //swap	d0
    signed short scaledSine = (sine * scaleVal)>>16;

    //add.w	$2C(a0),d0
    word newY = scaledSine + ptrgetobjvariableword(0x2C, obj);  //0x2C = current, shifted height of platform due to Plat_Move
		
    //move.w	d0,obY(a0)
    obj->Y = newY;
}   //rts	
//; End of function Plat_Nudge

//; ---------------------------------------------------------------------------
//; Subroutine to	move platforms
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

void (*index[13])() = { type00, type01, type02, type03, type04, type05, type06, type07, type08, type00, type0A, type0B, type0C };

//Plat_Move:				; XREF: Plat_Action; Plat_Action2
void Plat_Move()
{
    //moveq	#0,d0
    //move.b	obSubtype(a0),d0
    //andi.w	#$F,d0
    byte platType = obj->Subtype & 0xF;
		
    //add.w	d0,d0
    word platRoutine = platType; //no scaling needed in c

    //move.w	@index(pc,d0.w),d1
    //jmp	@index(pc,d1.w)
    (*index[platRoutine])();
}   //; End of function Plat_Move

//; ===========================================================================

//; ===========================================================================

//@type00:
void type00()
{
    //rts			; platform 00 doesn't move
}   //; ===========================================================================

//@type05:
void type05()
{
    //move.w	$32(a0),d0
    word startX = ptrgetobjvariableword(0x32, obj);

    //move.b	obAngle(a0),d1	; load platform-motion variable
    //neg.b	d1		; reverse platform-motion
    //addi.b	#$40,d1
    signed char shiftX = -obj->Angle + 0x40;

    //bra.s	@type01_move
    type01_move(startX, shiftX);

}   //; ===========================================================================

//@type01:
void type01()
{
    //move.w	$32(a0),d0
    word startX = ptrgetobjvariableword(0x32, obj);
		
    //move.b	obAngle(a0),d1	; load platform-motion variable
    //subi.b	#$40,d1
    signed char shiftX = obj->Angle - 0x40;

    type01_move(startX, shiftX);
}

//@type01_move:
void type01_move(word startX, signed char shiftX)
{
    //ext.w	d1
    signed short _shiftX = shiftX;

    //add.w	d1,d0
    word newX = startX + _shiftX;

    //move.w	d0,obX(a0)	; change position on x-axis
    obj->X = newX;

    //bra.w	@chgmotion
    chgmotion();             //update x-shift value with global oscillation values
}

//; ===========================================================================
//@type0C:
void type0C()
{
    //move.w	$34(a0),d0
    word startY = ptrgetobjvariableword(0x34, obj);

    //move.b	(v_oscillate+$E).w,d1 ; load platform-motion variable
    signed char motion = v_oscillate[0xE];

    //neg.b	d1		; reverse platform-motion
    //addi.b	#$30,d1
    signed char shiftY = -motion + 0x30;
		
    //bra.s	@type02_move
    type02_move(startY, shiftY);

}   //; ===========================================================================

//@type0B:
void type0B()
{
    //move.w	$34(a0),d0
    word startY = ptrgetobjvariableword(0x34, obj);

    //move.b	(v_oscillate+$E).w,d1 ; load platform-motion variable
    signed char motion = v_oscillate[0xE];

    //subi.b	#$30,d1
    signed char shiftY = motion - 0x30;
		
    //bra.s	@type02_move
    type02_move(startY, shiftY);

}   //; ===========================================================================

//@type06:
void type06()
{
    //move.w	$34(a0),d0
    word startY = ptrgetobjvariableword(0x34, obj);

    //move.b	obAngle(a0),d1	; load platform-motion variable
    //neg.b	d1		; reverse platform-motion
    //addi.b	#$40,d1
    signed char shiftY = -obj->Angle + 0x40;                    //shift value in phase with type 01 & 05
		
    //bra.s	@type02_move
    type02_move(startY, shiftY);
}   //; ===========================================================================

//@type02:
void type02()
{
    //move.w	$34(a0),d0
    word startY = ptrgetobjvariableword(0x34, obj);

    //move.b	obAngle(a0),d1	; load platform-motion variable
    //subi.b	#$40,d1
    signed char shiftY = obj->Angle - 0x40;                    //shift value in phase with type 01 & 05
		
    //bra.s	@type02_move
    type02_move(startY, shiftY);
}

void type02_move(word startY, signed char shiftY)
{
    //ext.w	d1
    signed short _shiftY = shiftY;

    //add.w	d1,d0
    word newY = startY + _shiftY;

    //move.w	d0,$2C(a0)	; change position on y-axis
    ptrsetobjvariableword(0x2C, obj, newY);

    //bra.w	@chgmotion
    chgmotion();

}   //; ===========================================================================

//@type03:
void type03()
{
    //tst.w	$3A(a0)		; is time delay	set?
    //bne.s	@type03_wait	; if yes, branch
    if (ptrgetobjvariableword(0x3A, obj) == 0)       //if time delay not set
    {
        //btst	#3,obStatus(a0)	; is Sonic standing on the platform?
        //beq.s	@type03_nomove	; if not, branch
        if ((obj->Status & 8) == 8)                  //and sonic standing on platform
        {
	    //move.w	#30,$3A(a0)	; set time delay to 0.5	seconds
            ptrsetobjvariableword(0x3A, 30);
        }
	
        //@type03_nomove:
	//rts
    }
    else
    {	
        //@type03_wait:
	//subq.w	#1,$3A(a0)	; subtract 1 from time
        ptrsubobjvariableword(0x3A, obj, 1);
   
	//bne.s	@type03_nomove	; if time is > 0, branch
        if (ptrgetobjvariableword(0x3A, obj) == 0)
        {
	    //move.w	#32,$3A(a0)
            ptrsetobjvariableword(0x3A, obj, 32);

	    //addq.b	#1,obSubtype(a0) ; change to type 04 (falling)
            obj->Subtype = obj->Subtype + 1;
        }
    }   //rts
}   //; ===========================================================================

//@type04:
void type04()
{
    //tst.w	$3A(a0)
    //beq.s	@loc_8048
    if (ptrgetobjvariableword(0x3A, obj) != 0)       //if time delay set
    {
        //subq.w	#1,$3A(a0)
        ptrsubobjvariableword(0x3A, obj, 1);

	//bne.s	@loc_8048
        if (ptrgetobjvariableword(0x3A, obj) == 0)
        {
	    //btst	#3,obStatus(a0)
            //beq.s	@loc_8042
            if ((obj->Status & 8) == 8)
            {
		//bset	#1,obStatus(a1)
                player.Status = player.Status | 2;

		//bclr	#3,obStatus(a1)
                player.Status = player.Status - (player.Status & 8);

		//move.b	#2,obRoutine(a1)
                player.Routine = 2;

		//bclr	#3,obStatus(a0)
                obj->Status = obj->Status - (obj->Status & 8);

		//clr.b	$25(a0)
                obj->Angle = (obj->Angle & 0x00FF);

		//move.w	obVelY(a0),obVelY(a1)
                player.VelocityY = obj->VelocityY;
            }
	    
            //@loc_8042:
	    //move.b	#8,obRoutine(a0)
            obj->Routine = 8;
        }
    }
 
    //@loc_8048:
    //move.l	$2C(a0),d3
    long platY = ptrgetobjvariablelong(0x2C, obj);

    //move.w	obVelY(a0),d0
    //ext.l	d0
    //asl.l	#8,d0
    long platShiftY = obj->VelocityY*256;

    //add.l	d0,d3
    long newY = platY + platShiftY;

    //move.l	d3,$2C(a0)
    ptrsetobjvariablelong(0x2C, obj, newY);

    //addi.w	#$38,obVelY(a0)
    obj->VelocityY = obj->VelocityY + 0x38;

    //move.w	(v_limitbtm2).w,d0
    //addi.w	#$E0,d0
    word platYLimit = v_limitbtm2 + 0xE0;

    //cmp.w	$2C(a0),d0
    //bcc.s	@locret_8074
    if (platYLimit < ptrgetobjvariableword(0x2C, obj) 
    {
        //move.b	#6,obRoutine(a0)
        obj->Routine = 6;
    }
	    
    //@locret_8074:
    //rts	
}   //; ===========================================================================

//@type07:
void type07()
{
    //tst.w	$3A(a0)		; is time delay	set?
    //bne.s	@type07_wait	; if yes, branch
    if (ptrgetobjvariableword(0x3A, obj) == 0)       //if time delay not set
    {
        //lea	(f_switch).w,a2	; load switch statuses
        byte *switchPtr = f_switch;

	//moveq	#0,d0
	//move.b	obSubtype(a0),d0 ; move object type ($x7) to d0
        byte platType = obj->Subtype;

	//lsr.w	#4,d0		; divide d0 by 8, round	down (16 actually lol)
        word switchIndex = platType / 16;

	//tst.b	(a2,d0.w)	; has switch no. d0 been pressed?
        //beq.s	@type07_nomove	; if not, branch
        if (switchPtr[switchIndex] != 0)
	{	
	    //move.w	#60,$3A(a0)	; set time delay to 1 second
            ptrsetobjvariableword(0x3A, obj, 60);
        }
	
        //@type07_nomove:
	//rts
    }
    else
    {	
        //@type07_wait:
	//subq.w	#1,$3A(a0)	; subtract 1 from time delay
        ptrsubobjvariableword(0x3A, obj, 1);

	//bne.s	@type07_nomove	; if time is > 0, branch
        if (ptrgetobjvariableword(0x3A, obj) == 0)
        {
	    //addq.b	#1,obSubtype(a0) ; change to type 08
	    obj->Subtype = obj->Subtype + 1;
        }
    }	//rts	
}   //; ===========================================================================

//@type08:
void type08()
{
    //subq.w	#2,$2C(a0)	; move platform	up
    ptrsubobjvariableword(0x2C, obj, 2);

    //move.w	$34(a0),d0
    word startY = ptrgetobjvariableword(0x34, obj);

    //subi.w	#$200,d0
    signed short endY = startY - 0x200;

    //cmp.w	$2C(a0),d0	; has platform moved $200 pixels?
    //bne.s	@type08_nostop	; if not, branch
    if (ptrgetobjvariableword(0x2C, obj) == endY)
    {
        //clr.b	obSubtype(a0)	; change to type 00 (stop moving)
        obj->Subtype = 0;
    }
    
    //@type08_nostop:
    //rts	
}   //; ===========================================================================

//@type0A:
void type0A()
{
    //move.w	$34(a0),d0
    word startY = ptrgetobjvariableword(0x34, obj);

    //move.b	obAngle(a0),d1	; load platform-motion variable
    //subi.b	#$40,d1
    byte shiftY = obj->Angle - 0x40;

    //ext.w	d1
    //asr.w	#1,d1
    word shiftYScaled = shiftY/2;

    //add.w	d1,d0
    word newY = startY + shiftYScaled;

    //move.w	d0,$2C(a0)	; change position on y-axis
    ptrsetobjvariableword(0x2C, obj, newY);

    chgmotion();
}

void chgmotion()
{
    //@chgmotion:
    //move.b	(v_oscillate+$1A).w,$26(a0) ; update platform-movement variable
    obj->Angle = v_oscillate[0x1A];

}   //rts	

//; ===========================================================================

//Plat_ChkDel:				; XREF: Plat_Action; Plat_Action2
void Plat_ChkDel()
{
    //out_of_range.s	Plat_Delete,$32(a0)
    if (out_of_range(ptrgetobjvariableword(0x32, obj))) { Plat_Delete(); }

}   //rts
	
//; ===========================================================================

//Plat_Delete:	; Routine 6
void Plat_Delete()
{
    //bra.w	DeleteObject
    DeleteObject(obj);
}
